#ifndef JASS_VALUE_H
#define JASS_VALUE_H

#include <memory>
#include <any>

namespace Ast
{
    namespace Visitor
    {

        class JassValueVisitor;

        class JassValue : std::enable_shared_from_this<JassValue>
        {
        public:
            virtual ~JassValue() = default;
            virtual std::any visit(std::shared_ptr<JassValueVisitor> visitor) {}
        };

        class IntegerJassValue : public JassValue
        {
        private:
            int value_;

        public:
            IntegerJassValue(int value) : value_(value) {}

            virtual int getValue() const { return value_; }

            virtual std::any visit(std::shared_ptr<JassValueVisitor> visitor);
            
            static std::shared_ptr<IntegerJassValue> ZERO();
        };
        
        class StringJassValue : public JassValue
        {
        private:
            std::string value_;

        public:
            StringJassValue(std::string value) : value_(std::move(value)) {}

            const std::string& getValue() { return this->value_; };

            static StringJassValue of(std::string value)
            {
                return StringJassValue(value);
            }

            virtual std::any visit(std::shared_ptr<JassValueVisitor> visitor);

            static std::shared_ptr<StringJassValue> EMPTY_STRING();
            static std::shared_ptr<StringJassValue> NULL_STRING();
        };

        class RealJassValue : public JassValue {
        private:
            double m_value;

        public:
            RealJassValue(double value) : m_value(value) {}

            double getValue() { return m_value; }

            static std::shared_ptr<RealJassValue> ZERO();
        };

        class BooleanJassValue : public JassValue {
        private:
            bool value_;

        public:
            BooleanJassValue(bool value) : value_(value) {}

            bool getValue() const { return value_; }

            static std::shared_ptr<BooleanJassValue> inverse(const std::shared_ptr<BooleanJassValue> value);
            static std::shared_ptr<BooleanJassValue> of(bool flag);

            static std::shared_ptr<BooleanJassValue> TRUE();
            static std::shared_ptr<BooleanJassValue> FALSE();
        };

    }
}

#endif // JASS_VALUE_H